package controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Locale;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import model.IExchangerModel;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import view.IExchangerView;
import fileFiltering.Utils;

public class ExchangerController implements IExchangerController {
	private IExchangerView view;
	private IExchangerModel model;

	public ExchangerController(IExchangerModel model, IExchangerView view) {
		this.model = model;
		this.view = view;
		this.model.setObserver(view);
		this.view.setControl(this);
	}

	@Override
	public void convertValue(String srcCurrency, String trgCurrency,
			double value) {
		// recupere les taux
		double srcRate = model.obtainRate(srcCurrency);
		double trgRate = model.obtainRate(trgCurrency);
		// faire la conversion
		double result = (value * srcRate) / trgRate;
		view.setResult(result);
	}

	@Override
	public void changeRate(String currency, double newRate) {
		model.modifyRate(currency, newRate);
		view.refresh();
	}

	@Override
	public void addCurrency(String currency, String abreviation, double rate,
			String iconPath) {
		model.addCurrency(currency, abreviation, rate, iconPath);
	}

	@Override
	public void removeCurrency(String currency) {
		model.removeCurrency(currency);
	}

	@Override
	public void saveSession() {
		// TODO Auto-generated method stub
	}

	@Override
	public void invertCurrencies(String srcCurrency, String trgCurrency) {
		System.out.println(srcCurrency + " " + trgCurrency);
		view.setTrgCurrency(srcCurrency);
		view.setSrcCurrency(trgCurrency);
	}

	@Override
	public void loadFile(File file) {
		if (!file.exists()) {
			this.view.showErrorMessageDialog("fileNotFound");
		} else {
			this.model.removeAllCurrencies();
			String ext = Utils.getExtension(file);
			if (ext.equals(Utils.csv)) {
				this.parseCSV(file);
			} else if (ext.equals(Utils.xml)) {
				this.parseXML(file);
			} else {
				this.view.showErrorMessageDialog("unvalidExt");
			}
		}
	}


	/**
	 * sauvegarde les devises dans un fichier de type specifie en parametre (csv ou xml)
	 */
	public void saveFile(File f, String mode) {
		String filePath = f.getAbsolutePath();
		String ext = (mode.equals(Utils.xml)) ? ".xml" : ".csv";
		filePath = (filePath.equals("")) ? "new" + ext : filePath + ext;
		if (mode.equals(Utils.xml)) {
			this.exportToXML(filePath);
		} else {
			this.exportToCSV(filePath);
		}
		this.view.showMessageDialog("fileSaved");
	}

	/**
	 * sauvegarde des devises dans un fichier CSV
	 * @param filePath
	 */
	private void exportToCSV(String filePath) {
		try {
			FileWriter fw = new FileWriter(filePath);
			String[][] infos = this.model.getAllCurrenciesInfos();
			for (String[] s : infos) {
				for (int k = 0; k < 3; k++) {
					fw.write(s[k + 1] + ",");
				}
				fw.write(s[0] + "\n");
			}
			fw.flush();
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * sauvegarde des devises dans un fichier XML
	 * @param filePath
	 */
	private void exportToXML(String filePath) {
		try {
			DocumentBuilder builder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			Document document = builder.newDocument();
			Element root = document.createElement("currencies");
			document.appendChild(root);
			String[][] infos = this.model.getAllCurrenciesInfos();
			for (String[] s : infos) {
				Element currency = document.createElement("currency");
				root.appendChild(currency);
				Element name = document.createElement("name");
				name.setTextContent(s[1]);
				Element code = document.createElement("code");
				code.setTextContent(s[2]);
				Element rate = document.createElement("rate");
				rate.setTextContent(s[3]);
				Element icon = document.createElement("icon");
				icon.setAttribute("src", s[0]);
				currency.appendChild(name);
				currency.appendChild(code);
				currency.appendChild(rate);
				currency.appendChild(icon);
			}
			TransformerFactory xformFactory = TransformerFactory.newInstance();
			Transformer idTransform = xformFactory.newTransformer();
			Source input = new DOMSource(document);
			Result output = new StreamResult(new File(filePath));
			idTransform.transform(input, output);

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Lit dans un fichier CSV et met le modele a jour avec des nouvelles devisses
	 * @param file
	 */
	private void parseCSV(File file) {
		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader(file));
			String tmp;
			while ((tmp = br.readLine()) != null) {
				String[] splitted = tmp.split(",");
				if (splitted.length == 4) {
					double ratio = Double.parseDouble(splitted[2]);
					this.addCurrency(splitted[0], splitted[1], ratio,
							splitted[3]);
				}
			}
			br.close();
			this.view.showMessageDialog("fileLoaded");
		} catch (FileNotFoundException e) {
			this.view.showErrorMessageDialog("fileNotFound");
		} catch (IOException e) {
			this.view.showErrorMessageDialog("ioException");
		}
	}

	private void parseXML(File file) {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		try {
			SAXParser parser = factory.newSAXParser();
			DefaultHandler currencies_managmer = new CurrenciesHandler(
					this.model, this.view);
			parser.parse(file, currencies_managmer);
		} catch (ParserConfigurationException e) {
			this.view.showErrorMessageDialog("parserConfig");
		} catch (SAXException e) {
			this.view.showErrorMessageDialog("saxException");
		} catch (IOException e) {
			this.view.showErrorMessageDialog("ioException");
		}
	}

	@Override
	public void setLocale(Locale locale) {
		Locale.setDefault(locale);
		view.refresh();
	}

	@Override
	public void refreshView() {
		view.refresh();
	}
}
